/*
 this：函数的执行主体（通俗来讲，就是谁把这个函数执行的），不是函数执行所处的上下文；我们都是去研究函数中的this，全局上下文中的this是window「前提：在浏览器环境下运行」！
   关于函数中的THIS到底是谁，大家只需要记住这几条规律即可
   @1 给元素进行事件绑定「DOM0/DOM2」
      当事件触发，绑定的方法执行，方法中的this是当前被操作的元素「给谁绑定的，this就是谁」
   @2 普通函数执行，看函数前面是否有“点”
      + 有：“点”前面是谁，函数中的this就是谁  
        例如：Array.prototype.push()，此时push中的this->Array.prototype
      + 没有：函数中的this是window(非严格模式)或者undefined(严格模式)
      + 像 自执行函数 或者 回调函数 等匿名函数，如果没有经过特殊的处理，那么函数中的this，一般都是window/undefined
   @3 构造函数执行（NEW执行），函数体中的this指向创建的实例对象
   @4 我们可以基于 call/apply/bind 强制改变函数中this的指向
   @5 箭头函数中没有this，所用到的this都是其“宿主环境（或上级上下文）”中的
 */

/*
 箭头函数 VS 普通函数
   + 最核心的区别：this「箭头函数中没有this」
   + 箭头函数没有 arguments 「可以基于“...”剩余运算符获取传递的实参」
   + 箭头函数没有 prototype 「不能被NEW执行」
   + 语法上的区别 「箭头函数写起来更方便/简单」
 项目中用谁？
   @1 不涉及到this的问题，用谁都可以「推荐使用箭头函数」
   @2 想作为一个构造函数，只能用普通函数
   @3 涉及this问题，用谁处理起来方便，就选择用谁「一般都是外层普通函数，内层箭头函数」
 */
let obj = {
    name: 'obj',
    /* fn: () => {
        console.log(this); //window
        console.log(this.name); //... 「不是“obj”」
    }, */
    // fn: function () {},
    fn() {
        console.log(this, this.name); //obj 、 “obj”

        /* let self = this;
        setTimeout(function () {
            console.log(this.name); //window.name
            console.log(self.name); //obj.name
        }, 1000); */

        setTimeout(() => {
            console.log(this.name); //obj.name
        }, 1000);
    }
};
obj.fn();


/*
box.onclick = function () {
    console.log(this); //this->box
}
box.addEventListener('click', function () {
    console.log(this); //this->box
})
*/

//=======================
/* 
let obj = {
    // 把自执行函数执行的返回值，赋值给 obj.fn 
    // obj.fn -> 0x001
    fn: (function () {
        return function () { //地址：0x001
            console.log(this);
        }
    })()
};
obj.fn(); //this->obj
let fn = obj.fn;
fn(); //this->window 
*/


/* var fullName = 'language'; //window.fullName=...
var obj = {
    fullName: 'javascript',
    prop: {
        getFullName: function () {
            return this.fullName;
        }
    }
};
console.log(obj.prop.getFullName()); //this->obj.prop => obj.prop.fullName => undefined
var test = obj.prop.getFullName;
console.log(test()); //this->window => window.fullName => 'language' */


/* var name = 'window';
var Tom = {
    name: "Tom",
    show: function () {
        console.log(this.name);
    },
    wait: function () {
        var fun = this.show;
        fun(); //this->window
    }
};
Tom.wait(); // this->Tom */


/* window.val = 1; //2 4
var json = {
    val: 10, //20
    dbl: function () {
        this.val *= 2;
    }
}
json.dbl(); //this->json => json.val *= 2 
var dbl = json.dbl;
dbl(); //this->window => window.val *= 2
json.dbl.call(window); //this->window => window.val *= 2
alert(window.val + json.val); //"24" */


/* (function () {
    var val = 1; //2
    var json = {
        val: 10,
        dbl: function () {
            val *= 2;
        }
    };
    json.dbl();
    alert(json.val + val); //"12"
})(); */